<?php
namespace App\Services\Wxpay\Pay;

use App\Services\Wxpay\Facades\Wxpay;
use App\Services\Wxpay\WxpayException;

/**
 *
 * JSAPI支付实现类
 * 该类实现了从微信公众平台获取code、通过code获取openid和access_token、
 * 生成jsapi支付js接口所需的参数、生成获取共享收货地址所需的参数
 *
 * 该类是微信支付提供的样例程序，商户可根据自己的需求修改，或者使用lib中的api自行开发
 *
 */
class JsApi
{

	protected $config;

	protected $api;

	public function __construct($config)
	{
		$this->config = $config;
		$this->api = new Api($config);
	}

	/**
	 *
	 * 网页授权接口微信服务器返回的数据，返回样例如下
	 * {
	 *  'access_token':'ACCESS_TOKEN',
	 *  'expires_in':7200,
	 *  'refresh_token':'REFRESH_TOKEN',
	 *  'openid':'OPENID',
	 *  'scope':'SCOPE',
	 *  'unionid': 'o6_bmasdasdsad6_2sgVt7hMZOPfL'
	 * }
	 * 其中access_token可用于获取共享收货地址
	 * openid是微信支付jsapi支付接口必须的参数
	 * @var array
	 */
	public $data = null;

	/**
	 *
	 * 通过跳转获取用户的openid，跳转流程如下：
	 * 1、设置自己需要调回的url及其其他参数，跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
	 * 2、微信服务处理完成之后会跳转回用户redirect_uri地址，此时会带上一些参数，如：code
	 *
	 * @return 用户的openid
	 */
	public function GetOpenid()
	{
		//通过code获得openid
		if (! isset($_GET['code'])) {
			//触发微信返回code码
			$baseUrl = urlencode('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . $_SERVER['QUERY_STRING']);
			$url = $this->__CreateOauthUrlForCode($baseUrl);
			Header('Location: ' . $url);
			exit();
		} else {
			//获取code码，以获取openid
			$code = $_GET['code'];
			$openid = $this->getOpenidFromMp($code);
			return $openid;
		}
	}

	/**
	 *
	 * 获取jsapi支付的参数
	 * @param array $UnifiedOrderResult 统一支付接口返回的数据
	 * @throws WxPayException
	 *
	 * @return json数据，可直接填入js函数作为参数
	 */
	public function GetJsApiParameters($UnifiedOrderResult)
	{
		if (! array_key_exists('appid', $UnifiedOrderResult) || ! array_key_exists('prepay_id', $UnifiedOrderResult) || $UnifiedOrderResult['prepay_id'] == '') {
			throw new WxPayException('参数错误');
		}
		$jsapi = new WxPayJsApiPay();
		$jsapi->setAppid($UnifiedOrderResult['appid']);
		$timeStamp = time();
		$jsapi->setTimeStamp($timeStamp);
		$jsapi->setNonceStr($this->api->getNonceStr());
		$jsapi->setPackage('prepay_id=' . $UnifiedOrderResult['prepay_id']);
		$jsapi->setSignType('MD5');
		$jsapi->setPaySign($jsapi->makeSign());
		$parameters = json_encode($jsapi->getValues());
		return $parameters;
	}

	/**
	 *
	 * 通过code从工作平台获取openid机器access_token
	 * @param string $code 微信跳转回来带上的code
	 *
	 * @return openid
	 */
	public function GetOpenidFromMp($code)
	{
		$url = $this->__CreateOauthUrlForOpenid($code);
		//初始化curl
		$ch = curl_init();
		//设置超时
		curl_setopt($ch, CURLOP_TIMEOUT, 30);
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
		curl_setopt($ch, CURLOPT_HEADER, FALSE);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
		if (Wxpay::getConfig('curl_proxy_host') != '0.0.0.0' && Wxpay::getConfig('curl_proxy_port') != 0) {
			curl_setopt($ch, CURLOPT_PROXY, Wxpay::getConfig('curl_proxy_host'));
			curl_setopt($ch, CURLOPT_PROXYPORT, Wxpay::getConfig('curl_proxy_port'));
		}
		//运行curl，结果以jason形式返回
		$res = curl_exec($ch);
		curl_close($ch);
		//取出openid
		$data = json_decode($res, true);
		$this->data = $data;
		$openid = $data['openid'];
		return $openid;
	}

	/**
	 *
	 * 拼接签名字符串
	 * @param array $urlObj
	 *
	 * @return 返回已经拼接好的字符串
	 */
	private function toUrlParams($urlObj)
	{
		$buff = '';
		foreach ($urlObj as $k => $v) {
			if ($k != 'sign') {
				$buff .= $k . '=' . $v . '&';
			}
		}

		$buff = trim($buff, '&');
		return $buff;
	}

	/**
	 *
	 * 获取地址js参数
	 *
	 * @return 获取共享收货地址js函数需要的参数，json格式可以直接做参数使用
	 */
	public function GetEditAddressParameters()
	{
		$getData = $this->data;
		$data = array();
		$data['appid'] = Wxpay::getConfig('appid');
		$data['url'] = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
		$time = time();
		$data['timestamp'] = '$time';
		$data['noncestr'] = '1234568';
		$data['accesstoken'] = $getData['access_token'];
		ksort($data);
		$params = $this->toUrlParams($data);
		$addrSign = sha1($params);

		$afterData = array(
			'addrSign' => $addrSign,
			'signType' => 'sha1',
			'scope' => 'jsapi_address',
			'appId' => Wxpay::getConfig('appid'),
			'timeStamp' => $data['timestamp'],
			'nonceStr' => $data['noncestr']
		);
		$parameters = json_encode($afterData);
		return $parameters;
	}

	/**
	 *
	 * 构造获取code的url连接
	 * @param string $redirectUrl 微信服务器回跳的url，需要url编码
	 *
	 * @return 返回构造好的url
	 */
	private function __CreateOauthUrlForCode($redirectUrl)
	{
		$urlObj['appid'] = Wxpay::getConfig('appid');
		$urlObj['redirect_uri'] = '$redirectUrl';
		$urlObj['response_type'] = 'code';
		$urlObj['scope'] = 'snsapi_base';
		$urlObj['state'] = 'STATE' . '#wechat_redirect';
		$bizString = $this->toUrlParams($urlObj);
		return 'https://open.weixin.qq.com/connect/oauth2/authorize?' . $bizString;
	}

	/**
	 *
	 * 构造获取open和access_toke的url地址
	 * @param string $code，微信跳转带回的code
	 *
	 * @return 请求的url
	 */
	private function __CreateOauthUrlForOpenid($code)
	{
		$urlObj['appid'] = Wxpay::getConfig('appid');
		$urlObj['secret'] = Wxpay::getConfig('appsecret');
		$urlObj['code'] = $code;
		$urlObj['grant_type'] = 'authorization_code';
		$bizString = $this->toUrlParams($urlObj);
		return 'https://api.weixin.qq.com/sns/oauth2/access_token?' . $bizString;
	}
}